package com.googlecode.agscrum.model.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.googlecode.agscrum.model.exceptions.GScrumDomainException;
import com.googlecode.agscrum.model.exceptions.MessageFactory;
import com.googlecode.agscrum.model.exceptions.GScrumDomainException.TypeMessage;
import com.googlecode.agscrum.model.repository.Repository;
import com.googlecode.agscrum.model.util.Criteria;
import com.googlecode.agscrum.model.validator.ValidatorUtil;

public class ServiceImpl<Entity, Key> implements Service<Entity, Key> {

	@Autowired
	protected MessageFactory messageFactory;

	public void setMessageFactory(MessageFactory messageFactory) {
		this.messageFactory = messageFactory;
	}

	@Autowired
	protected ValidatorUtil validatorUtil;

	public void setValidatorUtil(ValidatorUtil validatorUtil) {
		this.validatorUtil = validatorUtil;
	}

	private Repository<Entity, Key> repository;

	public Repository<Entity, Key> getRepository() {
		return repository;
	}

	public void setRepository(Repository<Entity, Key> repository) {
		this.repository = repository;
	}

	@Override
	@Transactional(readOnly = true)
	public List<Entity> findAll() {
		return getRepository().findAll();
	}

	@Override
	@Transactional(readOnly = true)
	public Entity findById(Key k) {
		return getRepository().findBy(k);
	}

	@Override
	@Transactional(rollbackFor = { GScrumDomainException.class, Exception.class })
	public void remove(Entity e) throws GScrumDomainException {
		try {
			getRepository().remove(e);
		} catch (GScrumDomainException gScrumDomainException) {
			throw gScrumDomainException;
		} catch (Exception e2) {
			e2.printStackTrace();
			throw new GScrumDomainException(messageFactory.createMessage(
					"default.error.remove", null, TypeMessage.ERROR), e2);
		}
	}

	@Override
	@Transactional(rollbackFor = { GScrumDomainException.class, Exception.class })
	public Entity save(Entity e) throws GScrumDomainException {
		try {
			validatorUtil.validate(e);
			return getRepository().save(e);
		} catch (GScrumDomainException gScrumDomainException) {
			throw gScrumDomainException;
		} catch (Exception e2) {
			e2.printStackTrace();
			throw new GScrumDomainException(messageFactory.createMessage(
					"default.error.save", null, TypeMessage.ERROR),e2);
		}

	}

	@Override
	@Transactional(readOnly = true)
	public List<Entity> readByCriteria(Criteria criteria, int initialPos,
			int finalPos) {
		return getRepository().readByCriteria(criteria, initialPos, finalPos);
	}

	@Override
	@Transactional(readOnly = true)
	public List<Entity> readByCriteria(Criteria criteria) {
		return getRepository().readByCriteria(criteria);
	}

	@Override
	@Transactional(readOnly = true)
	public Long totalOfByCriteria(Criteria criteria) {
		return getRepository().totalOfByCriteria(criteria);
	}

}
